home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / sw / sw_comm.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  13.4 KB  |  560 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <stream.h>
  20. #include <string.h>
  21. #include "sw.h"
  22. #include "extern.h"
  23. #include "main.h"
  24. #include "ship.h"
  25. #include "control.h"
  26. #include "resources.h"
  27. #include "sound.h"
  28. #include <unistd.h>
  29. #include <sys/socket.h>
  30. #include <netdb.h>
  31. #include <errno.h>
  32. // ADDED 08/11/93:
  33. #include <CC/osfcn.h>
  34.  
  35. //
  36. // Broadcast communication stuff
  37. //
  38.  
  39. static int            infoSocket;
  40. static struct sockaddr_in    infoAddr;
  41.  
  42. int            openBroadcast(int port)
  43. {
  44.   infoSocket = openBroadcastSocket(port, &infoAddr);
  45.   return (infoSocket != -1);
  46. }
  47.  
  48. void            closeBroadcast()
  49. {
  50.   close(infoSocket);
  51. }
  52.  
  53. int            sendBroadcast(const ShipInfo& si)
  54. {
  55.   BroadcastPacket p;
  56.   p.serverId = server()->serverId();
  57.   p.length = sizeof(si);
  58.   p.message = si;
  59.  
  60.   return (sendto(infoSocket, (void*)&p, sizeof(p), 0, &infoAddr,
  61.                     sizeof(infoAddr)) == sizeof(p));
  62. }
  63.  
  64. int            recvBroadcast(ShipInfo& si)
  65. {
  66.   BroadcastPacket    p;
  67.   struct sockaddr_in    from;
  68.   int            fromlen;
  69.   int            c;
  70.     
  71.   do {
  72.     fromlen = sizeof(from);
  73.     c = recvfrom(infoSocket, (void*)&p, sizeof(p), 0, &from, &fromlen);
  74.     if (c < 0) {                // error getting message
  75.       if (errno == EWOULDBLOCK)            // don't worry about it
  76.     return FALSE;
  77.       else {
  78.     perror("recvbroadcast");
  79.     return FALSE;
  80.       }
  81.     }
  82.     if (c == 0) return FALSE;            // no message
  83.   } while (NetId(from.sin_addr) == server()->hostId() ||
  84.         NetId(p.serverId) != server()->serverId());
  85.   si = p.message;
  86.  
  87.   return TRUE;
  88. }
  89.  
  90. void            handleBroadcastMessages()
  91. {
  92.   ShipInfo si;
  93.   while (recvBroadcast(si)) {
  94.     ShipObject* s = getPlayer(lookupPlayer(NetId(si.myId)));
  95.     if (self(s)) continue;            // ignore my messages
  96.     s->read(si);
  97.   }
  98. }
  99.  
  100. //
  101. // Server message handling
  102. //
  103.  
  104. void            handleServerMessages()
  105. {
  106.   const SwAnyMessage* any;
  107.   while (server()->receive() != SwNone) {
  108.     any = server()->get();
  109.     switch (server()->type()) {
  110.       case SwAddPlayer: {
  111.     const SwAddPlayerMessage* m =
  112.             (const SwAddPlayerMessage*)&(any->addPlayer);
  113.     if (self(m->p.id)) break;        // don't add myself
  114.     ShipObject* n = makeShip(m->p.shipClass,(InAddr &)m->p.id, m->p.team, m->p.name);
  115.     n->reset();
  116.     addPlayer(n);
  117.     break;
  118.       }
  119.       case SwRemovePlayer: {
  120.     const SwRemovePlayerMessage* m =
  121.             (const SwRemovePlayerMessage*)&(any->removePlayer);
  122.     int p = lookupPlayer((InAddr &)m->id);
  123.     ShipObject* s = getPlayer(p);
  124.     if (s && !self(s))            // don't remove unknown or me
  125.       removePlayer(p);
  126.     break;
  127.       }
  128.       case SwFlagUpdate: {
  129.     const SwFlagUpdateMessage* m =
  130.             (const SwFlagUpdateMessage*)&(any->flagUpdate);
  131.     setTeam(m->info);
  132.     break;
  133.       }
  134.       case SwFlagGrabbed: {
  135.     const SwFlagGrabbedMessage* m =
  136.             (const SwFlagGrabbedMessage*)&(any->flagGrabbed);
  137.     ShipObject* s = getPlayer(lookupPlayer(NetId((InAddr &)m->grabber)));
  138.     setTeam(m->info);
  139.     if (m->info.team == myShip->team() && m->info.state == FlagOnShip) {
  140.       if (s) {
  141.         if (s->team() != myShip->team())    // enemy has my flag!
  142.           soundPlay(EnemyGrabSound);
  143.       }
  144.       else {
  145.         // dunno, unknown person has my flag!  what to do?
  146.       }
  147.     }
  148.     if (self(s)) {                // I grabbed flag
  149.       s->flag(m->info.team);
  150.       flagChanged();
  151.       server()->send("grabbed %s flag", s->flag());
  152.       soundPlay(GrabSound);
  153.     }
  154.     break;
  155.       }
  156.       case SwFlagDropped: {
  157.     const SwFlagDroppedMessage* m =
  158.             (const SwFlagDroppedMessage*)&(any->flagDropped);
  159.     ShipObject* s = getPlayer(lookupPlayer(NetId((InAddr&)m->dropper)));
  160.     setTeam(m->info);
  161.     if (self(s)) {                // I grabbed flag
  162.       server()->send("dropped %s flag", m->info.team);
  163.       s->flag(NoTeam);
  164.       flagChanged();
  165.       soundPlay(DropSound);
  166.     }
  167.     break;
  168.       }
  169.       case SwFlagCaptured: {
  170.     const SwFlagCapturedMessage* m =
  171.             (const SwFlagCapturedMessage*)&(any->flagCaptured);
  172.     setTeam(m->flagTeam);
  173.     setTeam(m->captorTeam);
  174.     int lost = (m->flagTeam.team == myShip->team()),
  175.          won = (m->captorTeam.team == myShip->team() &&
  176.                 myShip->flag() == m->flagTeam.team);
  177.     if (lost) {                // my flag captured
  178.       wasFlagCaptured = TRUE;
  179.       if (won) {                //  took my flag into enemy base
  180.         server()->send("took my flag into enemy base");
  181.         myShip->flag(NoTeam);
  182.         flagChanged();
  183.       }
  184.       myShip->explodeShip(NetId());        //  I'm dead -- no killer
  185.       soundPlay(FlagLostSound);
  186.     }
  187.     else if (won) {                // I captured it    
  188.       server()->send("captured %s flag", myShip->flag());
  189.       myShip->flag(NoTeam);
  190.       flagChanged();
  191.       soundPlay(FlagWonSound);
  192.     }
  193.     scoreChanged();
  194.     break;
  195.       }
  196.       case SwHit: {
  197.     const SwHitMessage* m = (const SwHitMessage*)&(any->hit);
  198.     if (self(m->victim)) {            // hit me or mine
  199.       if (m->missileNum == -1)        //  hit ship
  200.         myShip->hitShield(*m);
  201.       else                    //  hit missile
  202.         myShip->explodeMissile(*m);
  203.     }
  204.     break;
  205.       }
  206.       case SwKilled: {
  207.     const SwKilledMessage* m = (const SwKilledMessage*)&(any->killed);
  208.     if (self(m->killer)) {            // I did killing
  209.       if (self(m->victim))            // I killed myself
  210.         server()->send("blew myself up");
  211.       else {
  212.         ShipObject* v = getPlayer(lookupPlayer(NetId((InAddr &)m->victim)));
  213.         if (v && v->team() == myShip->team()) {
  214.           server()->send("destroyed teammate %s (%s)", NetId((InAddr &)m->victim));
  215.           myShip->shipInfo().lost++;
  216.         }
  217.         else {
  218.           server()->send("destroyed %s (%s)", NetId((InAddr &)m->victim));
  219.           myShip->shipInfo().won++;
  220.        }
  221.       }
  222.     }
  223.     if (self(m->victim)) {            // I died
  224.       myShip->shipInfo().lost++;
  225.       soundPlay(KilledSound);
  226.     }
  227.     scoreChanged();
  228.     break;
  229.       }
  230.       case SwMessage: {
  231.     static char msg[256], msg2[256];
  232.     const SwMessageMessage* m = (const SwMessageMessage*)&(any->message);
  233.     ShipObject* p = getPlayer(lookupPlayer((InAddr &)m->source));
  234.     sprintf(msg, "%s (%s): %s", p ? p->name() : "???",
  235.                 p ? teamName(p->team()) : "???", m->msg);
  236.  
  237.     // put other ship name in if necessary
  238.     if (!NetId((InAddr &)m->target).isAny()) {    // about someone in particular
  239.       p = getPlayer(lookupPlayer((InAddr &)m->target));
  240.       sprintf(msg2, msg, p ? p->name() : "???",
  241.                 p ? teamName(p->team()) : "???");
  242.       addMessage(msg2);
  243.     }
  244.     else if (m->team != NoTeam) {        // about a particular team
  245.       sprintf(msg2, msg, teamName(m->team));
  246.       addMessage(msg2);
  247.     }
  248.     else                    // general message
  249.       addMessage(msg);
  250.     break;
  251.       }
  252.       case SwWorld:
  253.     // shouldn't happen (handled in open)
  254.     break;
  255.     }
  256.   }
  257. }
  258.  
  259. //
  260. // Server stuff
  261. //
  262.  
  263. SwServer::SwServer(const char* serverName)
  264. {
  265.   // get my host address
  266.   init();
  267.   if (status != NotConnected) return;
  268.  
  269.   // get server host address
  270.   struct hostent* he = gethostbyname(serverName);
  271.   if (!he) {
  272.     cerr << serverName << " not in host database\n";
  273.     status = NoSuchServer;
  274.   }
  275.   else {
  276.     serverNetId = NetId((const char*)(he->h_addr));
  277.     status = NotConnected;
  278.   }
  279. }
  280.  
  281. SwServer::SwServer(NetId serverId)
  282. {
  283.   // get my host address
  284.   init();
  285.   if (status != NotConnected) return;
  286.  
  287.   // store server address (assume it's valid)
  288.   serverNetId = serverId;
  289. }
  290.  
  291. SwServer::~SwServer()
  292. {
  293.   close();
  294. }
  295.  
  296. void            SwServer::init()
  297. {
  298.   // get my host name
  299.   char hostname[100];
  300.   if (gethostname(hostname, sizeof(hostname)) < 0) {
  301.     cerr << "can't get my host name\n";
  302.     status = OtherError;
  303.     return;
  304.   }
  305.  
  306.   // get my host address from name
  307.   struct hostent* he = gethostbyname(hostname);
  308.   if (!he) {
  309.     cerr << "my host name (" << hostname << ") not in host database!\n";
  310.     status = OtherError;
  311.     return;
  312.   }
  313.  
  314.   // store my host address
  315.   hostNetId = NetId((const char*)(he->h_addr));
  316.  
  317.   // initialize stuff
  318.   FD_ZERO(&read_set);
  319.   fd = -1;
  320.   status = NotConnected;
  321.   messageOut.length = 0;
  322.   messageOut.type = SwNone;
  323.   messageIn.type = SwNone;
  324. }
  325.  
  326. int            SwServer::open(const ShipObject* s)
  327. {
  328.   if (status == Connected) return TRUE;        // already connected
  329.   if (status != NotConnected) return FALSE;    // not ready to connect
  330.   if (!s) return FALSE;                // no ship
  331.  
  332.   // make temporary connection to find port for permanent connection
  333.   struct sockaddr_in addr;
  334.   fd = socket(AF_INET, SOCK_STREAM, 0);
  335.   if (fd == -1) {
  336.     perror("couldn't make get port socket");
  337.     return FALSE;
  338.   }
  339.   addr.sin_family = AF_INET;
  340.   addr.sin_port = SERVERPORT;
  341.   addr.sin_addr = serverNetId;
  342.   if (connect(fd, (const void*)&addr, sizeof(addr)) == -1) {
  343.     perror("couldn't connect get port socket");
  344.     ::close(fd);
  345.     return FALSE;
  346.   }
  347.   addr.sin_family = AF_INET;
  348.   addr.sin_addr = serverNetId;
  349.   int i = read(fd, (void*)&(addr.sin_port), sizeof(addr.sin_port));
  350.   ::close(fd);
  351.   fd = -1;
  352.  
  353.   // see if we're allowed to join
  354.   if (i < sizeof(addr.sin_port)) {
  355.     perror("couldn't get direct port number");
  356.     return FALSE;
  357.   }
  358.   else if (addr.sin_port == 0) {
  359.     fprintf(stderr, "Too many players.  Sorry.\n");
  360.     return FALSE;
  361.   }
  362.  
  363.   // open permanent connection to server
  364.   fd = socket(AF_INET, SOCK_STREAM, 0);
  365.   if (fd == -1) {
  366.     perror("couldn't make direct socket");
  367.     return FALSE;
  368.   }
  369.   if (connect(fd, (const void*)&addr, sizeof(addr)) == -1) {
  370.     perror("couldn't connect direct socket");
  371.     ::close(fd);
  372.     fd = -1;
  373.     return FALSE;
  374.   }
  375.   status = Connected;
  376.  
  377.   messageOut.type = SwJoin;
  378.   messageOut.any.join.p.id = s->id();
  379.   messageOut.any.join.p.team = s->team();
  380.   strcpy(messageOut.any.join.p.name, s->name());
  381.   messageOut.any.join.p.shipClass = s->shipClass();
  382.   send();
  383.  
  384.   getWorld();
  385.  
  386.   return TRUE;
  387. }
  388.  
  389. void            SwServer::close()
  390. {
  391.   if (status != Connected) return;        // not connected
  392.  
  393.   messageOut.type = SwQuit;
  394.   send();
  395.   status = NotConnected;
  396. }
  397.  
  398. int            SwServer::state() const
  399. {
  400.   return status;
  401. }
  402.  
  403. NetId            SwServer::serverId() const
  404. {
  405.   return serverNetId;
  406. }
  407.  
  408. NetId            SwServer::hostId() const
  409. {
  410.   return hostNetId;
  411. }
  412.  
  413. void            SwServer::getWorld()
  414. {
  415.   do {
  416.     messageOut.type = SwGetWorld;
  417.     send();
  418.     if (receive(TRUE) == SwWorld) {
  419.       switch (messageIn.any.world.type) {
  420.     case WorldTeam:
  421.       setTeam(messageIn.any.world.info.team);
  422.       break;
  423.     case WorldPlayer: {
  424.       if (NetId(messageIn.any.world.info.player.id) == hostNetId) break;
  425.       ShipObject* n = makeShip(messageIn.any.world.info.player.shipClass,
  426.                 messageIn.any.world.info.player.id,
  427.                 messageIn.any.world.info.player.team,
  428.                 messageIn.any.world.info.player.name);
  429.       n->reset();
  430.       addPlayer(n);
  431.       break;
  432.     }
  433.       }
  434.     }
  435.   } while (type() == SwWorld && messageIn.any.world.count > 0 &&
  436.                         status == Connected);
  437. }
  438.  
  439. void            SwServer::send(const SwAliveMessage& m)
  440. {
  441.   messageOut.type = SwAlive;
  442.   messageOut.any.alive = m;
  443.   send();
  444. }
  445.  
  446. void            SwServer::send(const SwHitMessage& m)
  447. {
  448.   messageOut.type = SwHit;
  449.   messageOut.any.hit = m;
  450.   send();
  451. }
  452.  
  453. void            SwServer::send(const SwKilledMessage& m)
  454. {
  455.   messageOut.type = SwKilled;
  456.   messageOut.any.killed = m;
  457.   send();
  458. }
  459.  
  460. void            SwServer::send(const SwGrabFlagMessage& m)
  461. {
  462.   messageOut.type = SwGrabFlag;
  463.   messageOut.any.grabFlag = m;
  464.   send();
  465. }
  466.  
  467. void            SwServer::send(const SwDropFlagMessage& m)
  468. {
  469.   messageOut.type = SwDropFlag;
  470.   messageOut.any.dropFlag = m;
  471.   send();
  472. }
  473.  
  474. void            SwServer::send(const SwCaptureFlagMessage& m)
  475. {
  476.   messageOut.type = SwCaptureFlag;
  477.   messageOut.any.captureFlag = m;
  478.   send();
  479. }
  480.  
  481. void            SwServer::send(const char* msg)
  482. {
  483.   messageOut.type = SwMessage;
  484.   strcpy(messageOut.any.message.msg, msg);
  485.   messageOut.any.message.source = hostNetId;
  486.   messageOut.any.message.target = NetId();    // not about anybody
  487.   messageOut.any.message.team = NoTeam;        // nor any team
  488.   send();
  489. }
  490.  
  491. void            SwServer::send(const char* msg, NetId aboutWhom)
  492. {
  493.   messageOut.type = SwMessage;
  494.   strcpy(messageOut.any.message.msg, msg);
  495.   messageOut.any.message.source = hostNetId;
  496.   messageOut.any.message.target = aboutWhom;    // about a player
  497.   messageOut.any.message.team = NoTeam;        // not about a team
  498.   send();
  499. }
  500.  
  501. void            SwServer::send(const char* msg, Team team)
  502. {
  503.   messageOut.type = SwMessage;
  504.   strcpy(messageOut.any.message.msg, msg);
  505.   messageOut.any.message.source = hostNetId;
  506.   messageOut.any.message.target = NetId();    // not about a player
  507.   messageOut.any.message.team = team;        // about a team
  508.   send();
  509. }
  510.  
  511. void            SwServer::send()
  512. {
  513.   // send messageOut to server
  514.   if (status != Connected) return;        // not ready to send
  515.  
  516.   if (write(fd, (void*)&messageOut, sizeof(messageOut)) < sizeof(messageOut)) {
  517.     ::close(fd);
  518.     fd = -1;
  519.     status = NotConnected;
  520.     messageIn.type = SwNone;
  521.   }
  522. }
  523.  
  524. ServerMessageType    SwServer::receive(int block)
  525. {
  526.   if (status == Connected) {
  527.     int nfound;
  528.     FD_SET(fd, &read_set);
  529.     if (block)
  530.       nfound = select(fd + 1, (FD_TYPE*)&read_set, NULL, NULL, NULL);
  531.     else {
  532.       struct timeval timeout;
  533.       timeout.tv_sec = 0;            // instant timeout (poll)
  534.       timeout.tv_usec = 0;
  535.       nfound = select(fd + 1, (FD_TYPE*)&read_set, NULL, NULL, &timeout);
  536.     }
  537.     if (nfound > 0) {
  538.       if (read(fd, (void*)&messageIn, sizeof(messageIn)) < sizeof(messageIn)) {
  539.     ::close(fd);                // lost connection
  540.     fd = -1;
  541.     status = NotConnected;
  542.     messageIn.type = SwNone;
  543.       }
  544.     }
  545.     else
  546.       messageIn.type = SwNone;
  547.   }
  548.   return messageIn.type;
  549. }
  550.  
  551. ServerMessageType    SwServer::type() const
  552. {
  553.   return messageIn.type;
  554. }
  555.  
  556. const SwAnyMessage*    SwServer::get() const
  557. {
  558.   return &(messageIn.any);
  559. }
  560.